<template>
  <div class="toolbar-container">
    <div class="left-toolbar">
      <el-button link type="primary" :disabled="undoDisabled" :title="i18nt('designer.toolbar.undoHint')"
                 @click="undoHistory">
        <svg-icon icon-class="undo"/>
      </el-button>
      <el-button link type="primary" :disabled="redoDisabled" :title="i18nt('designer.toolbar.redoHint')"
                 @click="redoHistory">
        <svg-icon icon-class="redo"/>
      </el-button>
      <el-button-group v-if="showLayoutTypeButton" style="margin-left: 20px">
        <el-button :type="layoutType === 'PC' ? 'info': ''" @click="changeLayoutType('PC')">
          {{ i18nt('designer.toolbar.pcLayout') }}
        </el-button>
        <el-button :type="layoutType === 'Pad' ? 'info': ''" @click="changeLayoutType('Pad')">
          {{ i18nt('designer.toolbar.padLayout') }}
        </el-button>
        <el-button :type="layoutType === 'H5' ? 'info': ''" @click="changeLayoutType('H5')">
          {{ i18nt('designer.toolbar.mobileLayout') }}
        </el-button>
      </el-button-group>
      <!--      <el-button style="margin-left: 20px" :title="i18nt('designer.toolbar.nodeTreeHint')" @click="showNodeTreeDrawer">
              <svg-icon icon-class="node-tree" /></el-button>-->
<!--      <el-button style="margin-left: 20px" title="数据结构" @click="showDataTreeDrawer">
        <svg-icon icon-class="tree"/>
      </el-button>-->
    </div>

    <el-drawer title="联动详情" direction="ltr" v-model="showLinkFunctionDrawerFlag"
               :modal="true" :size="600" append-to-body
               :destroy-on-close="true" class="node-tree-drawer">
        <div v-for="item in linkDataList" :key="item.name" style="line-height: 30px">{{item.linkFunctionDes}}</div>
    </el-drawer>

    <el-drawer title="数据结构" direction="ltr" v-model="showDataTreeDrawerFlag" draggable
               :modal="true" :size="480" append-to-body
               :destroy-on-close="true" class="node-tree-drawer">
<!--      <el-tree ref="dataTree" :data="dataTreeData" node-key="id" default-expand-all highlight-current class="node-tree"
               @node-drop="showDataTreeDrop"
               :allow-drop="allowDrop"
               style="-moz-user-select: none; -khtml-user-select: none; user-select: none;"
               icon-class="el-icon-arrow-right"></el-tree>-->
      <el-tree draggable :allow-drop="dropAllow" @node-drop="dragSuccess" ref="tree" :data="dataTreeData"
               default-expand-all node-key="id" highlight-current>
        <template #default="{ node, data }">
        <span class="custom-tree-node">
          <span>{{ node.data.fieldName }}</span>
        </span>
        </template>
      </el-tree>
    </el-drawer>

    <el-drawer :title="i18nt('designer.toolbar.nodeTreeTitle')" direction="ltr" v-model="showNodeTreeDrawerFlag"
               :modal="true" :size="280" append-to-body
               :destroy-on-close="true" class="node-tree-drawer">
      <el-tree ref="nodeTree" :data="nodeTreeData" node-key="id" default-expand-all highlight-current class="node-tree"
               icon-class="el-icon-arrow-right" @node-click="onNodeTreeClick"></el-tree>
    </el-drawer>

    <div class="right-toolbar">
      <el-scrollbar>
        <div class="right-toolbar-con">
          <div class="title">{{ designer.formConfig.frame.title }}({{designer.formConfig.frame.printSetting.companyName}})</div>
<!--          <el-button link type="primary" @click="showLinkDrawer">
            <svg-icon icon-class="cascader-field"/>
            联动详情
          </el-button>-->
          <el-button link type="primary" @click="saveData">
            <svg-icon icon-class="save"/>
            保存
          </el-button>
          <el-button link type="primary" @click="closeWindow()">
            <svg-icon icon-class="back"/>
            返回
          </el-button>
          <el-button v-if="showToolButton('clearDesignerButton')" link type="primary" @click="clearFormWidget">
            <svg-icon icon-class="el-delete"/>
            {{ i18nt('designer.toolbar.clear') }}
          </el-button>
          <el-button v-if="showToolButton('previewFormButton')" link type="primary" @click="previewForm">
            <svg-icon icon-class="el-view"/>
            {{ i18nt('designer.toolbar.preview') }}
          </el-button>
          <el-button v-if="showToolButton('importJsonButton')" link type="primary" @click="importJson">
            {{ i18nt('designer.toolbar.importJson') }}
          </el-button>
          <el-button v-if="showToolButton('exportJsonButton')" link type="primary" @click="exportJson">
            {{ i18nt('designer.toolbar.exportJson') }}
          </el-button>
          <el-button v-if="showToolButton('exportCodeButton')" link type="primary" @click="exportCode">
            {{ i18nt('designer.toolbar.exportCode') }}
          </el-button>
          <el-button v-if="showToolButton('generateSFCButton')" link type="primary" @click="generateSFC">
            <svg-icon icon-class="vue-sfc"/>
            {{ i18nt('designer.toolbar.generateSFC') }}
          </el-button>
          <template v-for="(idx, slotName) in $slots">
            <slot :name="slotName"></slot>
          </template>
        </div>
      </el-scrollbar>
    </div>

    <div v-if="showPreviewDialogFlag" class="" v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.toolbar.preview')" v-model="showPreviewDialogFlag"
                 :show-close="true" :close-on-click-modal="false" :close-on-press-escape="false" center
                 :destroy-on-close="true" :append-to-body="true"
                 class="drag-dialog small-padding-dialog vf-preview-dialog" width="75%"
                 :fullscreen="(layoutType === 'H5') || (layoutType === 'Pad')">
        <div>
          <div class="form-render-wrapper"
               :class="[layoutType === 'H5' ? 'h5-layout' : (layoutType === 'Pad' ? 'pad-layout' : '')]">
            <VFormRender ref="preForm" :form-json="formJson" :form-data="testFormData" :preview-state="true"
                         :option-data="testOptionData" :global-dsv="designerDsv"
                         @appendButtonClick="testOnAppendButtonClick" @buttonClick="testOnButtonClick"
                         @dataTableSelectionChange="testDTSC" @operationButtonClick="testOBC"
                         @myEmitTest="onMyEmitTest"
                         @formChange="handleFormChange">
              <template #slot1>
                <div>test1</div>
              </template>
              <template #slot2>
                <div>test2</div>
              </template>
              <template #slot3>
                <div>test3</div>
              </template>
              <template #slot4>
                <div>test4</div>
              </template>
              <template #slot5>
                <div>test5</div>
              </template>
            </VFormRender>
          </div>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" @click="getFormData">{{ i18nt('designer.hint.getFormData') }}</el-button>
            <el-button type="primary" @click="resetForm">{{ i18nt('designer.hint.resetForm') }}</el-button>
            <el-button type="primary" @click="setFormDisabled">{{ i18nt('designer.hint.disableForm') }}</el-button>
            <el-button type="primary" @click="setFormEnabled">{{ i18nt('designer.hint.enableForm') }}</el-button>
            <el-button type="primary" plain @click="switchReadMode">{{ i18nt('designer.hint.switchReadMode') }}
            </el-button>
            <el-button @click="showPreviewDialogFlag = false">{{ i18nt('designer.hint.closePreview') }}</el-button>
            <el-button v-if="false" @click="testSetFormJson">setFormJson</el-button>
            <el-button v-if="false" @click="testSubFormHide">Test SFH</el-button>
            <el-button v-if="false" @click="testSetFormData">Test SFD</el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div v-if="showImportJsonDialogFlag" class=""
         v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.toolbar.importJson')" v-model="showImportJsonDialogFlag"
                 :show-close="true" class="drag-dialog small-padding-dialog" :append-to-body="true" center
                 :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
        <el-alert type="info" :title="i18nt('designer.hint.importJsonHint')" show-icon class="alert-padding"></el-alert>
        <code-editor :mode="'json'" :readonly="false" v-model="importTemplate"></code-editor>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" @click="doJsonImport">
              {{ i18nt('designer.hint.import') }}
            </el-button>
            <el-button @click="showImportJsonDialogFlag = false">
              {{ i18nt('designer.hint.cancel') }}
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div v-if="showExportJsonDialogFlag" class=""
         v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.toolbar.exportJson')" v-model="showExportJsonDialogFlag"
                 :show-close="true" class="drag-dialog small-padding-dialog" center append-to-body
                 :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
        <code-editor :mode="'json'" :readonly="true" v-model="jsonContent"></code-editor>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" class="copy-json-btn" :data-clipboard-text="jsonRawContent" @click="copyFormJson">
              {{ i18nt('designer.hint.copyJson') }}
            </el-button>
            <el-button @click="saveFormJson">{{ i18nt('designer.hint.saveFormJson') }}</el-button>
            <el-button @click="showExportJsonDialogFlag = false">
              {{ i18nt('designer.hint.closePreview') }}
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div v-if="showExportCodeDialogFlag" class=""
         v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.toolbar.exportCode')" v-model="showExportCodeDialogFlag"
                 :show-close="true" class="drag-dialog small-padding-dialog" center append-to-body
                 width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
        <el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeCodeTab">
          <el-tab-pane label="Vue" name="vue">
            <code-editor :mode="'html'" :readonly="true" v-model="vueCode" :user-worker="false"></code-editor>
          </el-tab-pane>
          <el-tab-pane label="HTML" name="html">
            <code-editor :mode="'html'" :readonly="true" v-model="htmlCode" :user-worker="false"></code-editor>
          </el-tab-pane>
        </el-tabs>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" class="copy-vue-btn" :data-clipboard-text="vueCode" @click="copyVueCode">
              {{ i18nt('designer.hint.copyVueCode') }}
            </el-button>
            <el-button type="primary" class="copy-html-btn" :data-clipboard-text="htmlCode" @click="copyHtmlCode">
              {{ i18nt('designer.hint.copyHtmlCode') }}
            </el-button>
            <el-button @click="saveVueCode">{{ i18nt('designer.hint.saveVueCode') }}</el-button>
            <el-button @click="saveHtmlCode">{{ i18nt('designer.hint.saveHtmlCode') }}</el-button>
            <el-button @click="showExportCodeDialogFlag = false">
              {{ i18nt('designer.hint.closePreview') }}
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div v-if="showFormDataDialogFlag" class=""
         v-drag="['.nested-drag-dialog.el-dialog', '.nested-drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.hint.exportFormData')" v-model="showFormDataDialogFlag"
                 :show-close="true" class="nested-drag-dialog dialog-title-light-bg" center
                 :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true"
                 :append-to-body="true">
        <div style="border: 1px solid #DCDFE6">
          <code-editor :mode="'json'" :readonly="true" v-model="formDataJson"></code-editor>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" class="copy-form-data-json-btn" :data-clipboard-text="formDataRawJson"
                       @click="copyFormDataJson">
              {{ i18nt('designer.hint.copyFormData') }}
            </el-button>
            <el-button @click="saveFormData">{{ i18nt('designer.hint.saveFormData') }}</el-button>
            <el-button @click="showFormDataDialogFlag = false">
              {{ i18nt('designer.hint.closePreview') }}
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div v-if="showExportSFCDialogFlag" class="" v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
      <el-dialog :title="i18nt('designer.toolbar.generateSFC')" v-model="showExportSFCDialogFlag" append-to-body
                 v-if="showExportSFCDialogFlag" :show-close="true" class="drag-dialog small-padding-dialog" center
                 width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
        <el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeSFCTab">
          <el-tab-pane label="Vue2" name="vue2">
            <code-editor :mode="'html'" :readonly="true" v-model="sfcCode" :user-worker="false"></code-editor>
          </el-tab-pane>
          <el-tab-pane label="Vue3" name="vue3">
            <code-editor :mode="'html'" :readonly="true" v-model="sfcCodeV3" :user-worker="false"></code-editor>
          </el-tab-pane>
        </el-tabs>
        <template #footer>
          <div class="dialog-footer">
            <el-button type="primary" class="copy-vue2-sfc-btn" :data-clipboard-text="sfcCode" @click="copyV2SFC">
              {{ i18nt('designer.hint.copyVue2SFC') }}
            </el-button>
            <el-button type="primary" class="copy-vue3-sfc-btn" :data-clipboard-text="sfcCodeV3" @click="copyV3SFC">
              {{ i18nt('designer.hint.copyVue3SFC') }}
            </el-button>
            <el-button @click="saveV2SFC">{{ i18nt('designer.hint.saveVue2SFC') }}</el-button>
            <el-button @click="saveV3SFC">{{ i18nt('designer.hint.saveVue3SFC') }}</el-button>
            <el-button @click="showExportSFCDialogFlag = false">
              {{ i18nt('designer.hint.closePreview') }}
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

  </div>
</template>

<script>
import VFormRender from '@/components/form-render/index'
import CodeEditor from '@/components/code-editor/index'
import SvgIcon from '@/components/svg-icon'
import Clipboard from 'clipboard'
import {
  deepClone,
  copyToClipboard,
  generateId,
  getQueryParam,
  traverseAllWidgets, addWindowResizeHandler, evalFn
} from "@/utils/util"
import i18n from '@/utils/i18n'
import {generateCode} from "@/utils/code-generator"
import {genSFC} from "@/utils/sfc-generator"
import loadBeautifier from "@/utils/beautifierLoader"
import {saveAs} from 'file-saver'

export default {
  name: "ToolbarPanel",
  mixins: [i18n],
  components: {
    VFormRender,
    CodeEditor,
    SvgIcon,
    Clipboard,
  },
  props: {
    designer: Object,
    globalDsv: {
      type: Object,
      default: () => ({})
    },
  },
  inject: ['getDesignerConfig', 'getTestOptionData','getContainerWidgets','closeMainWindow'],
  data() {
    return {
      formJson: {},
      designerConfig: this.getDesignerConfig(),

      toolbarWidth: 450,
      showPreviewDialogFlag: false,
      showImportJsonDialogFlag: false,
      showExportJsonDialogFlag: false,
      showExportCodeDialogFlag: false,
      showFormDataDialogFlag: false,
      showExportSFCDialogFlag: false,
      showNodeTreeDrawerFlag: false,
      showDataTreeDrawerFlag: false,
      showLinkFunctionDrawerFlag: false,

      linkDataList:[],
      dataTreeData:[],
      nodeTreeData: [],
      formReadonlyFlag: false,

      importTemplate: '',
      jsonContent: '',
      jsonRawContent: '',

      formDataJson: '',
      formDataRawJson: '',

      vueCode: '',
      htmlCode: '',

      sfcCode: '',
      sfcCodeV3: '',

      activeCodeTab: 'vue',
      activeSFCTab: 'vue2',

      testFormData: {
        // 'userName': '666888',
        // 'productItems': [
        //   {'pName': 'iPhone12', 'pNum': 10},
        //   {'pName': 'P50', 'pNum': 16},
        // ]

        'select62173': 2,
      },

    }
  },
  computed: {
    undoDisabled() {
      return !this.designer.undoEnabled()
    },

    redoDisabled() {
      return !this.designer.redoEnabled()
    },

    layoutType() {
      return this.designer.getLayoutType()
    },

    designerDsv() {
      return this.globalDsv
    },

    testOptionData() {
      return this.getTestOptionData()
    },

    showLayoutTypeButton() {
      if (this.designerConfig['layoutTypeButton'] === undefined) {
        return true
      }

      return !!this.designerConfig['layoutTypeButton']
    },

  },
  watch: {
    'designer.widgetList': {
      deep: true,
      handler(val) {
        //console.log('test-----', val)
        //this.refreshNodeTree()
      }
    },

  },
  mounted() {
  },
  methods: {
    showToolButton(configName) {
      if (this.designerConfig[configName] === undefined) {
        return true
      }

      return !!this.designerConfig[configName]
    },

    buildTreeNodeOfWidget(widget, treeNode) {
      let curNode = {
        id: widget.id,
        label: widget.options.label || widget.type,
        type: widget.type,
        //selectable: true,
      }
      treeNode.push(curNode)

      if (widget.category === undefined) {
        return
      }

      curNode.children = []
      if (widget.type === 'grid') {
        widget.cols.map(col => {
          let colNode = {
            id: col.id,
            label: col.options.name || widget.type,
            type: widget.type,
            children: []
          }
          curNode.children.push(colNode)
          col.widgetList.map(wChild => {
            this.buildTreeNodeOfWidget(wChild, colNode.children)
          })
        })
      } else if (widget.type === 'table') {
        //TODO: 需要考虑合并单元格！！
        widget.rows.map(row => {
          let rowNode = {
            id: row.id,
            label: 'table-row',
            type: widget.type,
            selectable: false,
            children: [],
          }
          curNode.children.push(rowNode)

          row.cols.map(cell => {
            if (!!cell.merged) {  //跳过合并单元格！！
              return
            }

            let rowChildren = rowNode.children
            let cellNode = {
              id: cell.id,
              label: 'table-cell',
              type: cell.type,
              children: []
            }
            rowChildren.push(cellNode)

            cell.widgetList.map(wChild => {
              this.buildTreeNodeOfWidget(wChild, cellNode.children)
            })
          })
        })
      } else if (widget.type === 'tab') {
        widget.tabs.map(tab => {
          let tabNode = {
            id: tab.id,
            label: tab.options.name || widget.type,
            type: widget.type,
            selectable: false,
            children: []
          }
          curNode.children.push(tabNode)
          tab.widgetList.map(wChild => {
            this.buildTreeNodeOfWidget(wChild, tabNode.children)
          })
        })
      } else if (widget.type === 'sub-form') {
        widget.widgetList.map(wChild => {
          this.buildTreeNodeOfWidget(wChild, curNode.children)
        })
      } else if (widget.category === 'container') {  //自定义容器
        widget.widgetList.map(wChild => {
          this.buildTreeNodeOfWidget(wChild, curNode.children)
        })
      }
    },

    refreshNodeTree() {
      this.nodeTreeData.length = 0
      this.designer.widgetList.forEach(wItem => {
        this.buildTreeNodeOfWidget(wItem, this.nodeTreeData)
      })
    },

    showNodeTreeDrawer() {
      this.refreshNodeTree()
      this.showNodeTreeDrawerFlag = true
      this.$nextTick(() => {
        if (!!this.designer.selectedId) {  //同步当前选中组件到节点树！！！
          this.$refs.nodeTree.setCurrentKey(this.designer.selectedId)
        }
      })
    },
    arrayToTree(data) {
      // 用于存储树的根节点
      let root = [];

      // 用于存储每个节点的引用
      let map = {};

      // 首先，创建所有节点的引用
      data.forEach(item => {
        map[item.fieldName] = { ...item, children: [] };
      });
      // 然后，构建树结构
      data.forEach(item => {
        const node = map[item.fieldName];
        if (!item.parentKeyName || !map[item.parentKeyName]) {
          // 如果 parentKeyName 不存在或者在 map 中找不到父节点，表示这是根节点
          root.push(node);
        } else {
          // 否则，找到其父节点，并将其添加到父节点的 children 列表中
          map[item.parentKeyName].children.push(node);
        }
      });
      return root;
    },

    getFormDataList(widgetList){
      let formDataList = [];
      widgetList.forEach(function (val) {
        if (!val.category && val.category != "container") {
          formDataList.push(val.options)
        }
      })
      return formDataList;
    },

    showDataTreeDrawer() {
      let widgetList = deepClone(this.designer.widgetList)
      let dataTreeData = []
      for (let i = 0; i < widgetList.length; i++) {
        let widget = widgetList[i];
        //仅在grid和table下的组件才会被记录进入系统
        if (widget.type == "table"){
          let funcDef = this.initTableData(widget,24);
          funcDef.children = funcDef.fieldDefs
          funcDef.label = funcDef.frame.title
          dataTreeData.push(funcDef)
        }
        if (widget.type == "grid"){
          let cols = widget.cols;
          for (let j = 0; j < cols.length; j++) {
            let colSpan = cols[j].options.span;
            let tables = cols[j].widgetList;
            for (let k = 0; k < tables.length; k++) {
              let table = tables[k]
              if (table.type == "table"){
                let funcDef = this.initTableData(table,colSpan);
                funcDef.children = funcDef.fieldDefs
                funcDef.label = funcDef.frame.title
                dataTreeData.push(funcDef)
              }
            }
          }
        }
      }
      this.dataTreeData = dataTreeData;
      this.showDataTreeDrawerFlag = true
    },
    dropAllow(draggingNode, dropNode, type) {
      return true;
    },
    addParentNames(json, parentName) {
      const self = this;
      let widgetRef = this.designer.formWidget.getWidgetRef(json.name);
      if (widgetRef){
        //容器组件不做处理。
        if (widgetRef.setParentKeyName){
          widgetRef.setParentKeyName(parentName)
        }
      }
      if (json.children.length > 0) {
        json.children.forEach(child => {
          self.addParentNames(child, json.fieldName);
        });
      }
    },
    // 拖拽成功时触发
    dragSuccess(draggingNode, dropNode, type, event) {
      //todo 便利父属性，设置其parentKeyName
      const self = this;
      this.dataTreeData.forEach(function (value) {
        self.addParentNames(value,null);
      })
    },
    /**
     *
     * @description
     * @author: 何慕嘉
     * date: 2024/7/1
     * @param widget:表格组件json，
     * @param widget:表格组件占的列
     * @param fyWidgets:自定义组件列表
     */
    initTableData(widget,colSpan,fyWidgets){
      let funcDef = widget.options
      let fieldList = [];
      funcDef.showType = "form";
      funcDef.colSpan = colSpan;
      funcDef.rowSpan = 0;
      funcDef.funcNo = funcDef.fieldName;
      let rows = widget.rows;
      let colsNum = 0
      for (let j = 0; j < rows.length; j++) {
        let cols = rows[j].cols;
        colsNum = cols.length;
        for (let k = 0; k < cols.length; k++) {
          let col = cols[k];
          col.widgetList.forEach(function (widget) {
            let field = widget.options
            field.rowSpan = col.options.rowspan
            field.colSpan = col.options.colspan
            field.fieldId = field.name
            fieldList.push(field)
          })
        }
      }
      funcDef.fieldDefs = this.arrayToTree(fieldList);
      funcDef.range={
        "arrangeRows": rows.length,
        "arrangeCols": colsNum
      }
      funcDef.customComponentConfigArgs = []
      if (fyWidgets){
        fyWidgets.forEach(function (val){
          if (funcDef.fieldName == val.parentForm){
            funcDef.customComponentConfigArgs.push(val)
          }
        })
      }
      return funcDef;
    },
    /**
     *
     * @description
     * @author: 何慕嘉
     * date: 2024/7/1
     * @param widget:grid组件json，
     * @param colSpan:grid组件占的列
     */
    initGridData(widget){
      let fieldList = [];
      let cols = widget.cols;
      for (let j = 0; j < cols.length; j++) {
        let col = cols[j];
        if (col.widgetList.length>0){
          col.widgetList.forEach(function (widget) {
            let field = widget.options
            if (widget.type != "fy"){
              field.rowSpan = 1
              field.colSpan = col.options.span
              field.fieldId = field.name
              field.fieldType = widget.aliasType
              fieldList.push(field)
            }else {
              //自定义组件
              let field = {...widget.options}
              field.customData = null;
              field.rowSpan = 1;
              field.colSpan = col.options.span;
              field.fieldType = widget.options.customType;
              field.fieldName = widget.options.fieldName;
              field.label = widget.options.label;
              field.customComponentConfigArg = {...widget.options.customData}
              fieldList.push(field)
            }
          })
        }else {
          fieldList.push({
            label:"",
            fieldType:"text",
            rowSpan:1,
            colSpan:col.options.span,
          })
        }
      }
      return fieldList;
    },
    /*initGridData(widget,colSpan,fyWidgets){
      console.log(widget)
      let funcDef = widget.options
      let fieldList = [];
      funcDef.showType = "form";
      funcDef.colSpan = colSpan;
      funcDef.rowSpan = 1;
      funcDef.funcNo = funcDef.fieldName;
      let cols = widget.cols;
      for (let j = 0; j < cols.length; j++) {
        let col = cols[j];
        col.widgetList.forEach(function (widget) {
          let field = widget.options
          field.rowSpan = 1
          field.colSpan = col.options.span
          field.fieldId = field.name
          fieldList.push(field)
        })
      }
      funcDef.fieldDefs = this.arrayToTree(fieldList);
      funcDef.range={
        "arrangeRows": 1,
        "arrangeCols": 24
      }
      funcDef.customComponentConfigArgs = []
      if (fyWidgets){
        fyWidgets.forEach(function (val){
          if (funcDef.fieldName == val.parentForm){
            funcDef.customComponentConfigArgs.push(val)
          }
        })
      }
      return funcDef;
    },*/
    closeWindow(){
      this.closeMainWindow();
    },
    initFYData(){
      let widgetList = deepClone(this.designer.widgetList)
      let formConfig = deepClone(this.designer.formConfig)
      /*      let fyWidgets = []
            this.getContainerWidgets().forEach(function (val){
              if (val.type == "fy"){
                fyWidgets.push(val.container.options);
              }
            })*/
      let fieldList = [];
      for (let i = 0; i < widgetList.length; i++) {
        let widget = widgetList[i];
        if (!widget.category){
          let field = widget.options
          field.rowSpan = 1;
          field.colSpan = 24;
          field.fieldId = field.name
          field.fieldType = widget.aliasType
          fieldList.push(field)
        }else if (widget.category == "container" && widget.type == "grid"){
          fieldList = fieldList.concat(this.initGridData(widget))
        }else if (widget.category == "container" && widget.type == "fy"){
          //自定义组件
          let field = {...widget.options}
          field.options = null;
          field.rowSpan = 1;
          field.colSpan = 24;
          field.fieldName = widget.options.fieldName;
          field.label = widget.options.label;
          field.fieldType = widget.options.customType
          let options = {...widget.options.customData};
          field.customComponentConfigArg = options;
          fieldList.push(field)
        }
      }
      //formData.fieldDefs = fieldList;
      /*      if (fyWidgets){
              fyWidgets.forEach(function (val){
                formData.customComponentConfigArgs.push(val)
              })
            }*/
      let formData = {
        masterRecordTableName:formConfig.masterRecordTableName,
        childRecordTableName:formConfig.childRecordTableName,
        //showType:"form",
        rowSpan:1,
        colSpan:24,
        funcNo:formConfig.funcNo,
        showIndex:formConfig.showIndex,
        frame:formConfig.frame,
        thirdPartyPostBack:formConfig.thirdPartyPostBack,
        returnParams:formConfig.returnParams,
        gridDef:formConfig.gridDef,
        customDBStatement:formConfig.customDBStatement,
        funcLayout:formConfig.funcLayout,
        formDef:{
          toolBar:formConfig.toolBar,
          btnBar:formConfig.btnBar,
          formFieldDefs:fieldList,
        }
      }

      return {formData,widgetList,formConfig}
    },
    findDuplicateFieldNames(arr) {
      const seen = new Set(); // 存储已经出现的fieldName值
      const duplicates = new Set(); // 存储重复的fieldName值

      for (let obj of arr) {
        if (obj.fieldName && obj.fieldType != "text"){
          if (seen.has(obj.fieldName)) {
            duplicates.add(obj.fieldName); // 如果Set中已经有这个fieldName，说明是重复的，添加到duplicates
          } else {
            seen.add(obj.fieldName); // 否则将fieldName添加到seen
          }
        }
      }
      return [...duplicates]; // 返回重复的fieldName数组
    },
    /**
     * 保存方法
     */
    saveData(){
      let fyData = this.initFYData();
      console.log(fyData)
      let arr = this.findDuplicateFieldNames(fyData.formData.formDef.formFieldDefs)
      if (arr.length > 0){
        this.$message.warning(this.i18nt(arr.join(",")+"字段出现重复！"))
        return
      }
      this.$emit('saveData', this.initFYData());
    },
    /*saveData(){
      let widgetList = deepClone(this.designer.widgetList)
      let formData = deepClone(this.designer.formConfig)
      let formConfig = deepClone(this.designer.formConfig)
      let fyWidgets = []
      this.getContainerWidgets().forEach(function (val){
        if (val.type == "fy"){
          fyWidgets.push(val.container.options);
        }
      })
      let funcDefs = [];
      for (let i = 0; i < widgetList.length; i++) {
        let widget = widgetList[i];
        //仅在grid和table下的组件才会被记录进入系统
        if (widget.type == "table"){
          let funcDef = this.initTableData(widget,24,fyWidgets);
          funcDefs.push(funcDef);
        }
        if (widget.type == "grid"){
          if (widget.options.gridType == "form"){
            let funcDef = this.initGridData(widget,24,fyWidgets);
            funcDefs.push(funcDef);
          }else if (widget.options.gridType == "grid"){
            let cols = widget.cols;
            for (let j = 0; j < cols.length; j++) {
              let colSpan = cols[j].options.span;
              let tables = cols[j].widgetList;
              for (let k = 0; k < tables.length; k++) {
                let table = tables[k]
                if (table.type == "table"){
                  let funcDef = this.initTableData(table,colSpan,fyWidgets);
                  funcDefs.push(funcDef);
                }else if (table.type == "grid" && table.options.gridType == "form"){
                  let funcDef = this.initGridData(table,colSpan,fyWidgets);
                  funcDefs.push(funcDef);
                }
              }
            }
          }
        }
      }
      formData.funcDefs = funcDefs;
      this.$emit('saveData', {formData,widgetList,formConfig});
    },*/
    showLinkDrawer(){
      let widgetList = deepClone(this.designer.widgetList)
      let formDataList = [];
      let dataMap = {}
      widgetList.forEach(function (val) {
        if (!val.category && val.category != "container") {
          formDataList.push(val.options)
          dataMap[val.options.name]=val.options
        }
      })
      let linkDataList = [];
      formDataList.forEach(function (data) {
        if (data.linkItem && (data.showValue || data.hideValue)){
          let linkItemNameList = [];
          data.linkItem.split(",").forEach(function (name) {
            let item = dataMap[name]
            if (item){
              linkItemNameList.push(item.label)
            }
          })
          if (linkItemNameList.length>0){
            let linkItemName = linkItemNameList.join(",");
/*            let fieldName = data.fieldName?data.fieldName:data.name
            let labelName = data.label+"("+data.name+"/"+fieldName+")";*/
            let des = "当字段（"+data.label+"）的值";
            if (data.showValue){
              des += "为"+data.showValue+"时，展示（"+linkItemName+"）字段；"
            }
            if (data.hideValue){
              des += "为"+data.hideValue+"时，隐藏（"+linkItemName+"）字段；"
            }
            data.linkFunctionDes = des;
            linkDataList.push(data);
          }
        }
      })
      this.linkDataList = linkDataList;
      this.showLinkFunctionDrawerFlag = true
    },

    undoHistory() {
      this.designer.undoHistoryStep()
      this.designer.emitEvent('canvas-undo', null)
    },

    redoHistory() {
      this.designer.redoHistoryStep()
      this.designer.emitEvent('canvas-redo', null)
    },

    changeLayoutType(newType) {
      this.designer.changeLayoutType(newType)
    },

    clearFormWidget() {
      this.designer.clearDesigner()
      this.designer.formWidget.clearWidgetRefList()

      this.designer.emitEvent('form-json-imported', [])  //通知其他组件
    },
    previewForm() {
      this.$emit('previewFYForm', this.initFYData());
    },
/*
    previewForm() {
      let widgetList = this.designer.widgetList
      let formDataList = [];
      let dataMap = {}
      widgetList.forEach(function (val) {
        if (!val.category && val.category != "container") {
          formDataList.push(val.options)
          dataMap[val.options.name]=val.options
        }
      })
      formDataList.forEach(function (data) {
        if (data.linkItem && (data.showValue || data.hideValue)){
          let itemList = []
          data.linkItem.split(",").forEach(function (name) {
            let item = dataMap[name]
            if (item){
              itemList.push(item)
            }
          })
          let onchange = "";
          itemList.forEach(function (item){
            onchange += "var " +item.name+"Widget = this.getWidgetRef('" +item.name+"');";
          })
          if (data.showValue){
            onchange += "if(value && Array.isArray(value)){";
            onchange +="console.log(value);"
              onchange += "if (value.includes(" +data.showValue+")){"
            onchange +="console.log(3243);"
              itemList.forEach(function (item){
                onchange += item.name+"Widget.setHidden(false);"
              })
              onchange +="}";
            onchange +=    "}else{";
              onchange += "if (value == " +data.showValue+") {"
              itemList.forEach(function (item){
                onchange += item.name+"Widget.setHidden(false);"
              })
              onchange +="}";
            onchange +=    "}";
          }
          if (data.hideValue){
            onchange += "if(value && Array.isArray(value)){";
              onchange += "if (value.includes(" +data.hideValue+")){"
              itemList.forEach(function (item){
                onchange += item.name+"Widget.setHidden(true);"
              })
              onchange +="}";
            onchange +=    "}else{";
              onchange += "if (value == " +data.hideValue+") {"
              itemList.forEach(function (item){
                onchange += item.name+"Widget.setHidden(true);"
              })
              onchange +="}";
            onchange +=    "}";
          }
          console.log(onchange);
          data.onChange = onchange;
        }
      })

      this.formJson.widgetList = deepClone(this.designer.widgetList)
      this.formJson.formConfig = deepClone(this.designer.formConfig)

      this.showPreviewDialogFlag = true
    },
*/

    saveAsFile(fileContent, defaultFileName) {
      this.$prompt(this.i18nt('designer.hint.fileNameForSave'), this.i18nt('designer.hint.saveFileTitle'), {
        inputValue: defaultFileName,
        closeOnClickModal: false,
        inputPlaceholder: this.i18nt('designer.hint.fileNameInputPlaceholder')
      }).then(({value}) => {
        if (!value) {
          value = defaultFileName
        }

        if (getQueryParam('vscode') == 1) {
          this.vsSaveFile(value, fileContent)
          return
        }

        const fileBlob = new Blob([fileContent], {type: 'text/plain;charset=utf-8'})
        saveAs(fileBlob, value)
      }).catch(() => {
        //
      })
    },

    vsSaveFile(fileName, fileContent) {
      const msgObj = {
        cmd: 'writeFile',
        data: {
          fileName,
          code: fileContent
        }
      }
      window.parent.postMessage(msgObj, '*')
    },

    importJson() {
      this.importTemplate = JSON.stringify(this.designer.getImportTemplate(), null, '  ')
      this.showImportJsonDialogFlag = true
    },

    doJsonImport() {
      try {
        let importObj = JSON.parse(this.importTemplate)
        //console.log('test import', this.importTemplate)
        if (!importObj || !importObj.formConfig) {
          throw new Error(this.i18nt('designer.hint.invalidJsonFormat'))
        }

        let fJsonVer = importObj.formConfig.jsonVersion
        if (!fJsonVer || (fJsonVer !== 3)) {
          throw new Error(this.i18nt('designer.hint.jsonVersionMismatch'))
        }

        this.designer.loadFormJson(importObj)

        this.showImportJsonDialogFlag = false
        this.$message.success(this.i18nt('designer.hint.importJsonSuccess'))

        this.designer.emitHistoryChange()
      } catch (ex) {
        this.$message.error(ex + '')
      }
    },

    exportJson() {
      let widgetList = deepClone(this.designer.widgetList)
      let formConfig = deepClone(this.designer.formConfig)
      this.jsonContent = JSON.stringify({widgetList, formConfig}, null, '  ')
      this.jsonRawContent = JSON.stringify({widgetList, formConfig})
      this.showExportJsonDialogFlag = true
    },

    copyFormJson(e) {
      copyToClipboard(this.jsonRawContent, e,
          this.$message,
          this.i18nt('designer.hint.copyJsonSuccess'),
          this.i18nt('designer.hint.copyJsonFail')
      )
    },

    saveFormJson() {
      this.saveAsFile(this.jsonContent, `vform${generateId()}.json`)
    },

    exportCode() {
      this.formJson.widgetList = deepClone(this.designer.widgetList)
      this.formJson.formConfig = deepClone(this.designer.formConfig)
      this.vueCode = generateCode(this.formJson)
      this.htmlCode = generateCode(this.formJson, 'html')
      this.showExportCodeDialogFlag = true
    },

    copyVueCode(e) {
      copyToClipboard(this.vueCode, e,
          this.$message,
          this.i18nt('designer.hint.copyVueCodeSuccess'),
          this.i18nt('designer.hint.copyVueCodeFail')
      )
    },

    copyHtmlCode(e) {
      copyToClipboard(this.htmlCode, e,
          this.$message,
          this.i18nt('designer.hint.copyHtmlCodeSuccess'),
          this.i18nt('designer.hint.copyHtmlCodeFail')
      )
    },

    saveVueCode() {
      this.saveAsFile(this.vueCode, `vform${generateId()}.vue`)
    },

    saveHtmlCode() {
      this.saveAsFile(this.htmlCode, `vform${generateId()}.html`)
    },

    generateSFC() {
      loadBeautifier(beautifier => {
        this.sfcCode = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier)
        this.sfcCodeV3 = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier, true)
        this.showExportSFCDialogFlag = true
      })
    },

    copyV2SFC(e) {
      copyToClipboard(this.sfcCode, e,
          this.$message,
          this.i18nt('designer.hint.copySFCSuccess'),
          this.i18nt('designer.hint.copySFCFail')
      )
    },

    copyV3SFC(e) {
      copyToClipboard(this.sfcCodeV3, e,
          this.$message,
          this.i18nt('designer.hint.copySFCSuccess'),
          this.i18nt('designer.hint.copySFCFail')
      )
    },

    saveV2SFC() {
      this.saveAsFile(this.sfcCode, `vformV2-${generateId()}.vue`)
    },

    saveV3SFC() {
      this.saveAsFile(this.sfcCodeV3, `vformV3-${generateId()}.vue`)
    },

    getFormData() {
      this.$refs['preForm'].getFormData().then(formData => {
        this.formDataJson = JSON.stringify(formData, null, '  ')
        this.formDataRawJson = JSON.stringify(formData)

        this.showFormDataDialogFlag = true
      }).catch(error => {
        this.$message.error(error)
      })
    },

    copyFormDataJson(e) {
      copyToClipboard(this.formDataRawJson, e,
          this.$message,
          this.i18nt('designer.hint.copyJsonSuccess'),
          this.i18nt('designer.hint.copyJsonFail')
      )
    },

    saveFormData() {
      this.saveAsFile(this.formDataJson, `formData${generateId()}.json`)
    },

    resetForm() {
      this.$refs['preForm'].resetForm()
    },

    setFormDisabled() {
      this.$refs['preForm'].disableForm()
    },

    setFormEnabled() {
      this.$refs['preForm'].enableForm()
    },

    switchReadMode() {
      this.formReadonlyFlag = !this.formReadonlyFlag
      this.$refs['preForm'].setReadMode(this.formReadonlyFlag)
    },

    testSetFormJson() {
      //let newJson = {"widgetList":[{"key":106933,"type":"input","icon":"text-field","formItemFlag":true,"options":{"name":"input40302","label":"input-new","labelAlign":"","type":"text","defaultValue":"","placeholder":"","columnWidth":"200px","size":"","labelWidth":null,"labelHidden":false,"readonly":false,"disabled":false,"hidden":false,"clearable":true,"showPassword":false,"required":false,"validation":"","validationHint":"","customClass":[],"labelIconClass":null,"labelIconPosition":"rear","labelTooltip":null,"minLength":null,"maxLength":null,"showWordLimit":false,"prefixIcon":"","suffixIcon":"","appendButton":false,"appendButtonDisabled":false,"buttonIcon":"custom-search","onCreated":"","onMounted":"","onInput":"","onChange":"","onFocus":"","onBlur":"","onValidate":""},"id":"input40302"}],"formConfig":{"modelName":"formData","refName":"vForm","rulesName":"rules","labelWidth":120,"labelPosition":"left","size":"","labelAlign":"label-left-align","cssCode":"","customClass":[],"functions":"","layoutType":"PC","jsonVersion":3,"onFormCreated":"","onFormMounted":"","onFormDataChange":""}}
      let newJson = {
        "widgetList": [{
          "key": 75094,
          "type": "input",
          "icon": "text-field",
          "formItemFlag": true,
          "options": {
            "name": "input30696",
            "label": "input",
            "labelAlign": "",
            "type": "text",
            "defaultValue": "",
            "placeholder": "",
            "columnWidth": "200px",
            "size": "",
            "labelWidth": null,
            "labelHidden": false,
            "readonly": false,
            "disabled": false,
            "hidden": false,
            "clearable": true,
            "showPassword": false,
            "required": false,
            "validation": "",
            "validationHint": "",
            "customClass": [],
            "labelIconClass": null,
            "labelIconPosition": "rear",
            "labelTooltip": null,
            "minLength": null,
            "maxLength": null,
            "showWordLimit": false,
            "prefixIcon": "",
            "suffixIcon": "",
            "appendButton": false,
            "appendButtonDisabled": false,
            "buttonIcon": "custom-search",
            "onCreated": "",
            "onMounted": "",
            "onInput": "",
            "onChange": "",
            "onFocus": "",
            "onBlur": "",
            "onValidate": ""
          },
          "id": "input30696"
        }],
        "formConfig": {
          "modelName": "formData",
          "refName": "vForm",
          "rulesName": "rules",
          "labelWidth": 120,
          "labelPosition": "left",
          "size": "",
          "labelAlign": "label-left-align",
          "cssCode": "",
          "customClass": "",
          "functions": "",
          "layoutType": "PC",
          "jsonVersion": 3,
          "onFormCreated": "",
          "onFormMounted": "",
          "onFormDataChange": ""
        }
      }
      //let newJson = {"widgetList":[{"key":70118,"type":"input","icon":"text-field","formItemFlag":true,"options":{"name":"input37241","label":"input","labelAlign":"","type":"text","defaultValue":"","placeholder":"","columnWidth":"200px","size":"","labelWidth":null,"labelHidden":false,"readonly":false,"disabled":false,"hidden":false,"clearable":true,"showPassword":false,"required":false,"validation":"","validationHint":"","customClass":[],"labelIconClass":null,"labelIconPosition":"rear","labelTooltip":null,"minLength":null,"maxLength":null,"showWordLimit":false,"prefixIcon":"","suffixIcon":"","appendButton":false,"appendButtonDisabled":false,"buttonIcon":"custom-search","onCreated":"","onMounted":"","onInput":"","onChange":"","onFocus":"","onBlur":"","onValidate":""},"id":"input37241"}],"formConfig":{"modelName":"formData","refName":"vForm","rulesName":"rules","labelWidth":150,"labelPosition":"left","size":"","labelAlign":"label-right-align","cssCode":"","customClass":"","functions":"","layoutType":"PC","jsonVersion":3,"onFormCreated":"","onFormMounted":"","onFormDataChange":""}}
      this.$refs['preForm'].setFormJson(newJson)
    },

    testSubFormHide() {
      this.$refs['preForm'].hideWidgets('input73220')
    },

    testSetFormData() {
      let testFormData = {
        "picTest01": [
          {
            "name": "QQ浏览器截图20200730103242.png",
            "url": "http://image-2021.test.upcdn.net/QQ浏览器截图20200730103242.png"
          },
          {
            "name": "QQ浏览器截图20201218155618.jpg",
            "url": "http://image-2021.test.upcdn.net/QQ浏览器截图20201218155618.jpg"
          }
        ],
        "fileTest01": [
          {
            "name": "吉林大学2019-2020《公文写作》大作业.doc",
            "url": "http://image-2021.test.upcdn.net/吉林大学2019-2020《公文写作》大作业.doc"
          },
          {
            "name": "资源包抵扣明细.xlsx",
            "url": "http://image-2021.test.upcdn.net/资源包抵扣明细.xlsx"
          }
        ]
      }
      this.$refs['preForm'].setFormData(testFormData)
    },

    handleFormChange(fieldName, newValue, oldValue, formModel) {
      /*
      console.log('---formChange start---')
      console.log('fieldName', fieldName)
      console.log('newValue', newValue)
      console.log('oldValue', oldValue)
      console.log('formModel', formModel)
      console.log('---formChange end---')
      */
    },

    testOnAppendButtonClick(clickedWidget) {
      console.log('test', clickedWidget)
    },

    testOnButtonClick(button) {
      console.log('test', button)
    },

    testDTSC(dt, s1, s2) {
      // console.log('test dt', dt)
      // console.log('test s1', s1)
      // console.log('test s2', s2)
    },

    testOBC(aa) {
      console.log('test=====', aa)
    },

    onMyEmitTest(aaa) {
      console.log('test emit', aaa)
    },

    findWidgetById(wId) {
      let foundW = null
      traverseAllWidgets(this.designer.widgetList, (w) => {
        if (w.id === wId) {
          foundW = w
        }
      })

      return foundW
    },

    onNodeTreeClick(nodeData, node, nodeEl) {
      //console.log('test', JSON.stringify(nodeData))

      if ((nodeData.selectable !== undefined) && !nodeData.selectable) {
        this.$message.info(this.i18nt('designer.hint.currentNodeCannotBeSelected'))
      } else {
        const selectedId = nodeData.id
        const foundW = this.findWidgetById(selectedId)
        if (!!foundW) {
          this.designer.setSelected(foundW)
        }
      }
    },

  }
}
</script>

<style lang="scss" scoped>
.toolbar-container {
  width: 100%;
}

.toolbar-container:after {
  display: block;
  content: "";
  clear: both;
}

.left-toolbar {
  display: flex;
  margin-top: 4px;
  float: left;
  font-size: 16px;
}

.right-toolbar {
  line-height: 42px;
  text-align: right;
  overflow: hidden;

  .right-toolbar-con {
    //display:inline-block;
    //text-align: left;
    display: flex;
    justify-content: flex-end;
    min-width: 450px;
    height: 42px;
  }

  :deep(.el-button) {
    margin-left: 10px;
  }

  :deep(.el-button--text) {
    font-size: 14px !important;
  }

  :deep(.svg-icon) {
    margin-left: 0;
    margin-right: 0.05em;
  }
}

.el-button i {
  margin-right: 3px;
}

.small-padding-dialog {
  :deep(.el-dialog__header) {
    //padding-top: 3px;
    //padding-bottom: 3px;
    background: #f1f2f3;
  }

  :deep(.el-dialog__body) {
    padding: 12px 15px 12px 15px;

    .el-alert.alert-padding {
      padding: 0 10px;
    }
  }

  :deep(.ace-container) {
    border: 1px solid #DCDFE6;
  }
}

.dialog-title-light-bg {
  :deep(.el-dialog__header) {
    background: #f1f2f3;
  }
}

.no-box-shadow {
  box-shadow: none;
}

.no-padding.el-tabs--border-card {
  :deep(.el-tabs__content) {
    padding: 0;
  }
}

.form-render-wrapper {
  //height: calc(100vh - 142px);
  //all: revert !important; /* 防止表单继承el-dialog等外部样式，未生效，原因不明？？ */
}

.form-render-wrapper.h5-layout {
  margin: 0 auto;
  width: 420px;
  border-radius: 15px;
  //border-width: 10px;
  box-shadow: 0 0 1px 10px #495060;
  height: calc(100vh - 175px);
  overflow-y: auto;
  overflow-x: hidden;
}

.form-render-wrapper.pad-layout {
  margin: 0 auto;
  width: 960px;
  border-radius: 15px;
  //border-width: 10px;
  box-shadow: 0 0 1px 10px #495060;
  height: calc(100vh - 175px);
  overflow-y: auto;
  overflow-x: hidden;
}

.node-tree-drawer {
  :deep(.el-drawer) {
    padding: 10px;
    overflow: auto;
  }

  :deep(.el-drawer__header) {
    margin-bottom: 12px;
    padding: 5px 5px 0;
  }

  :deep(.el-drawer__body) {
    padding-left: 5px;
  }
}

/*.node-tree-scroll-bar {*/
/*  height: 100%;*/
/*  overflow: auto;*/
/*}*/

:deep(.node-tree) {
  .el-tree > .el-tree-node:after {
    border-top: none;
  }

  .el-tree-node {
    position: relative;
    padding-left: 12px;
  }

  .el-tree-node__content {
    padding-left: 0 !important;
  }

  .el-tree-node__expand-icon.is-leaf {
    display: none;
  }

  .el-tree-node__children {
    padding-left: 12px;
    overflow: visible !important; /* 加入此行让el-tree宽度自动撑开，超出宽度el-draw自动出现水平滚动条！ */
  }

  .el-tree-node :last-child:before {
    height: 38px;
  }

  .el-tree > .el-tree-node:before {
    border-left: none;
  }

  .el-tree > .el-tree-node:after {
    border-top: none;
  }

  .el-tree-node:before {
    content: "";
    left: -4px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .el-tree-node:after {
    content: "";
    left: -4px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .el-tree-node:before {
    border-left: 1px dashed #4386c6;
    bottom: 0px;
    height: 100%;
    top: -10px;
    width: 1px;
  }

  .el-tree-node:after {
    border-top: 1px dashed #4386c6;
    height: 20px;
    top: 12px;
    width: 16px;
  }

  .el-tree-node.is-current > .el-tree-node__content {
    background: #c2d6ea !important;
  }

  .el-tree-node__expand-icon {
    margin-left: -3px;
    padding: 6px 6px 6px 0px;
    font-size: 16px;
  }
}
.title{
  flex: 1;
  text-align: center;
}
</style>
